home *** CD-ROM | disk | FTP | other *** search
/ Network PC / Network PC.iso / amiga utilities / communication / internet / amitcp3.0b / src.lha / src / util / ping / ping.c next >
Encoding:
C/C++ Source or Header  |  1996-09-08  |  38.5 KB  |  1,397 lines

  1. RCS_ID_C="$Id: ping.c,v 3.7 1994/03/07 22:46:33 ppessi Exp $";
  2. /*
  3.  * ping.c -- network connectivity testing tool
  4.  *
  5.  * Last modified: Tue Mar  8 00:46:06 1994 ppessi
  6.  */
  7.  
  8. #include "ping_rev.h"
  9.  
  10. static const char version[] = VERSTAG " "
  11. "Copyright © 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>\n"
  12. "Helsinki University of Technology, Finland.\n"
  13. "Copyright © 1983 The Regents of the University of California.\n"
  14. "All rights reserved.\n";
  15.  
  16. /****** netutil.doc/ping ****************************************************
  17.  
  18.     NAME
  19.         ping - send ICMP ECHO_REQUEST packets to network hosts
  20.  
  21.     SYNOPSIS
  22.         ping [-dfnqrvR] [-c count] [-i wait] [-l preload] [-p pattern]
  23.              [-s packetsize] [-L [ hosts ]] host
  24.  
  25.     DESCRIPTION
  26.         Ping uses the ICMP protocol's mandatory ECHO_REQUEST datagram to
  27.         elicit an ICMP ECHO_RESPONSE from a host or gateway.  ECHO_REQUEST
  28.         datagrams (``pings'') have an IP and ICMP header, followed by a
  29.         ``struct timeval'' and then an arbitrary number of ``pad'' bytes
  30.         used to fill out the packet.  The options are as follows: Other
  31.         options are:
  32.  
  33.         -c count
  34.                 Stop after sending (and receiving) count ECHO_RESPONSE
  35.                 packets.
  36.  
  37.         -d      Set the SO_DEBUG option on the socket being used.
  38.  
  39.         -f      Flood ping.  Outputs packets as fast as they come back or
  40.                 one hundred times per second, whichever is more.  For every
  41.                 ECHO_REQUEST sent a period ``.'' is printed, while for ever
  42.                 ECHO_REPLY received a backspace is printed.  This provides a
  43.                 rapid display of how many packets are being dropped.  Only
  44.                 the super-user may use this option.  This can be very hard
  45.                 on a network and should be used with caution.
  46.  
  47.         -i wait
  48.                 Wait wait seconds between sending each packet. The default
  49.                 is to wait for one second between each packet.  This option
  50.                 is incompatible with the -f option.
  51.  
  52.         -L [hosts]
  53.             Use loose routing IP option.  Includes IPOPT_LSRR option in
  54.                 the ECHO_REQUEST packet with all specified hosts in the
  55.                 route.  Many hosts wont support loose routing, such a host
  56.                 can either ignore or return the loose routed ICMP packet in
  57.                 the middle of the route.
  58.  
  59.         -l preload
  60.                 If preload is specified, ping sends that many packets as
  61.                 fast as possible before falling into its normal mode of
  62.                 behavior.
  63.  
  64.         -n      Numeric output only.  No attempt will be made to lookup
  65.                 symbolic names for host addresses.
  66.  
  67.         -p pattern
  68.                 You may specify up to 16 ``pad'' bytes to fill out the
  69.                 packet you send.  This is useful for diagnosing
  70.                 data-dependent problems in a network.  For example, ``-p
  71.                 ff'' will cause the sent packet to be filled with all ones.
  72.  
  73.         -q      Quiet output.  Nothing is displayed except the summary lines
  74.                 at startup time and when finished.
  75.  
  76.         -R      Record route.  Includes the RECORD_ROUTE option in the
  77.                 ECHO_REQUEST packet and displays the route buffer on
  78.                 returned packets.  Note that the IP header is only large
  79.                 enough for nine such routes.  Many hosts ignore or discard
  80.                 this option.
  81.  
  82.         -r      Bypass the normal routing tables and send directly to a host
  83.                 on an attached network.  If the host is not on a
  84.                 directly-attached network, an error is returned.  This
  85.                 option can be used to ping a local host through an interface
  86.                 that has no route through it.
  87.  
  88.         -s packetsize
  89.                 Specifies the number of data bytes to be sent.  The default
  90.                 is 56, which translates into 64 ICMP data bytes when
  91.                 combined with the 8 bytes of ICMP header data.
  92.  
  93.         -v      Verbose output.  ICMP packets other than ECHO_RESPONSE that
  94.                 are received are listed.
  95.  
  96.         When using ping for fault isolation, it should first be run on the
  97.         local host, to verify that the local network interface is up and
  98.         running.  Then, hosts and gateways further and further away should
  99.         be ``pinged''.  Round-trip times and packet loss statistics are
  100.         computed.  If duplicate packets are received, they are not included
  101.         in the packet loss calculation, although the round trip time of
  102.         these packets is used in calculating the minimum/average/maximum
  103.         round-trip time numbers.  When the specified number of packets have
  104.         been sent (and received) or if the program is terminated with a
  105.         SIGINT, a brief summary is displayed.
  106.  
  107.         This program is intended for use in network testing, measurement and
  108.         management.  Because of the load it can impose on the network, it is
  109.         unwise to use ping during normal operations or from automated
  110.         scripts.
  111.  
  112.     ICMP PACKET DETAILS
  113.         An IP header without options is 20 bytes.  An ICMP ECHO_REQUEST
  114.         packet contains an additional 8 bytes worth of ICMP header followed
  115.         by an arbitrary amount of data.  When a packetsize is given, this
  116.         indicated the size of this extra piece of data (the default is 56).
  117.         Thus the amount of data received inside of an IP packet of type ICMP
  118.         ECHO_REPLY will always be 8 bytes more than the requested data space
  119.         (the ICMP header).
  120.  
  121.         If the data space is at least eight bytes large, ping uses the first
  122.         eight bytes of this space to include a timestamp which it uses in
  123.         the computation of round trip times.  If less than eight bytes of
  124.         pad are specified, no round trip times are given.
  125.  
  126.     DUPLICATE AND DAMAGED PACKETS
  127.         Ping will report duplicate and damaged packets.  Duplicate packets
  128.         should never occur, and seem to be caused by inappropriate
  129.         link-level retransmissions.  Duplicates may occur in many situations
  130.         and are rarely (if ever) a good sign, although the presence of low
  131.         levels of duplicates may not always be cause for alarm.
  132.  
  133.         Damaged packets are obviously serious cause for alarm and often
  134.         indicate broken hardware somewhere in the ping packet's path (in the
  135.         network or in the hosts).
  136.  
  137.     TRYING DIFFERENT DATA PATTERNS
  138.         The (inter)network layer should never treat packets differently
  139.         depending on the data contained in the data portion.  Unfortunately,
  140.         data-dependent problems have been known to sneak into networks and
  141.         remain undetected for long periods of time.  In many cases the
  142.         particular pattern that will have problems is something that doesn't
  143.         have sufficient ``transitions'', such as all ones or all zeros, or a
  144.         pattern right at the edge, such as almost all zeros.  It isn't
  145.         necessarily enough to specify a data pattern of all zeros (for
  146.         example) on the command line because the pattern that is of interest
  147.         is at the data link level, and the relationship between what you
  148.         type and what the controllers transmit can be complicated.
  149.  
  150.         This means that if you have a data-dependent problem you will
  151.         probably have to do a lot of testing to find it.  If you are lucky,
  152.         you may manage to find a file that either can't be sent across your
  153.         network or that takes much longer to transfer than other similar
  154.         length files.  You can then examine this file for repeated patterns
  155.         that you can test using the -p option of ping.
  156.  
  157.     TTL DETAILS
  158.         The TTL value of an IP packet represents the maximum number of IP
  159.         routers that the packet can go through before being thrown away.  In
  160.         current practice you can expect each router in the Internet to
  161.         decrement the TTL field by exactly one.
  162.  
  163.         The TCP/IP specification states that the TTL field for TCP packets
  164.         should be set to 60, but many systems use smaller values (4.3 BSD
  165.         uses 30, 4.2 used 15). The AmiTCP/IP uses normally TTL value 30.
  166.  
  167.         The maximum possible value of this field is 255, and most systems
  168.         set the TTL field of ICMP ECHO_REQUEST packets to 255.  This is why
  169.         you will find you can ``ping'' some hosts, but not reach them with
  170.         telnet or ftp.
  171.  
  172.         In normal operation ping prints the ttl value from the packet it re-
  173.         ceives.  When a remote system receives a ping packet, it can do one
  174.         of three things with the TTL field in its response:
  175.  
  176.         ·   Not change it; this is what Berkeley Unix systems did before the
  177.             4.3BSD-Tahoe release.  In this case the TTL value in the
  178.             received packet will be 255 minus the number of routers in the
  179.             round-trip path.
  180.  
  181.         ·   Set it to 255; this is what AmiTCP/IP and current Berkeley Unix
  182.             systems do.  In this case the TTL value in the received packet
  183.             will be 255 minus the number of routers in the path from the
  184.             remote system to the pinging host.
  185.  
  186.         ·   Set it to some other value.  Some machines use the same value
  187.             for ICMP packets that they use for TCP packets, for example
  188.             either 30 or 60.  Others may use completely wild values.
  189.  
  190.     LOOSE SOURCE ROUTING DETAILS 
  191.         When a packet is routed with loose routing in IP, the destination
  192.         address of datagram is originally set to the first address in the
  193.         routing list.  When the datagram reaches its destination, the
  194.         destination address is changed to the next address in the list and
  195.         the datagram is routed to that destination. After the whole routing
  196.         list is exhausted, the datagram is handled to upper-level protocols.
  197.  
  198.         The loose routing options can be ignored by hosts between the
  199.         gateways in the loose routing list.  However, if the host in the
  200.         list don't understand loose routing, it may think that the datagram
  201.         is destined to it and respond to it.  Also, many hosts simply drop
  202.         the packets with IP options.
  203.  
  204.     BUGS
  205.         Many Hosts and Gateways ignore the RECORD_ROUTE and
  206.         LOOSE_SOURCE_ROUTING options.
  207.  
  208.         The maximum IP header length is too small for options like
  209.         RECORD_ROUTE to be completely useful.  There's not much that that
  210.         can be done about this, however.
  211.  
  212.         Flood pinging is not recommended in general, and flood pinging the
  213.         broadcast address should only be done under very controlled
  214.         conditions.
  215.  
  216.     SEE ALSO
  217.         netstat,  ifconfig
  218.  
  219.     AUTHOR
  220.         Mike Muuss, U. S. Army Ballistic Research Laboratory, December, 1983
  221.  
  222.         The ping command appeared in 4.3BSD.
  223.  
  224.         The loose routing and working record route options were added by
  225.         Pekka Pessi, AmiTCP/IP Group, Helsinki Univ. of Technology.
  226.  
  227. *****************************************************************************
  228. * */
  229.  
  230. /*
  231.  *            P I N G . C
  232.  *
  233.  * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility,
  234.  * measure round-trip-delays and packet loss across network paths.
  235.  *
  236.  * Author -
  237.  *    Mike Muuss
  238.  *    U. S. Army Ballistic Research Laboratory
  239.  *    December, 1983
  240.  *
  241.  * Status -
  242.  *    Public Domain.  Distribution Unlimited.
  243.  * Bugs -
  244.  *    More statistics could always be gathered.
  245.  */
  246.  
  247. #ifdef AMIGA
  248. #if defined(__SASC)
  249. #include <proto/socket.h>
  250. #elif __GNUC__
  251. #include <inline/socket.h>
  252. #else
  253. #include <clib/socket_protos.h>
  254. #endif
  255. #define ioctl IoctlSocket
  256.  
  257. /* Correct prototype for the CheckIO.
  258.  * (The one in clib/exec_protos.h has wrong return value type: BOOL (16 bits)
  259.  * instead of a pointer (32 bits)!)
  260.  */
  261. struct IORequest * CheckIO(struct IORequest *req);
  262.  
  263. #endif /* AMIGA */
  264.  
  265. #include <sys/param.h>
  266. #include <sys/socket.h>
  267. #include <sys/time.h>
  268.  
  269. #ifdef __SASC
  270. #include <fcntl.h>
  271. #include <signal.h>
  272. #else
  273. #include <sys/file.h>
  274. #include <sys/signal.h>
  275. #endif
  276.  
  277. #include <netinet/in_systm.h>
  278. #include <netinet/in.h>
  279. #include <netinet/ip.h>
  280. #include <netinet/ip_icmp.h>
  281. #include <netinet/ip_var.h>
  282. #include <netdb.h>
  283. #include <arpa/inet.h>
  284. #include <unistd.h>
  285. #include <stdio.h>
  286. #include <ctype.h>
  287. #include <errno.h>
  288. #include <string.h>
  289. #include <stdlib.h>
  290.  
  291. #define    DEFDATALEN    (64 - 8)    /* default data length */
  292. #define    MAXIPLEN    60
  293. #define    MAXICMPLEN    76
  294. #define    MAXPACKET    (65536 - 60 - 8)/* max packet size */
  295. #define    MAXWAIT        10        /* max seconds to wait for response */
  296. #define    NROUTES        9        /* number of record route slots */
  297.  
  298. #define    A(bit)        rcvd_tbl[(bit)>>3]    /* identify byte in array */
  299. #define    B(bit)        (1 << ((bit) & 0x07))    /* identify bit in byte */
  300. #define    SET(bit)    (A(bit) |= B(bit))
  301. #define    CLR(bit)    (A(bit) &= (~B(bit)))
  302. #define    TST(bit)    (A(bit) & B(bit))
  303.  
  304. /* various options */
  305. int options;
  306. #define    F_FLOOD        0x001
  307. #define    F_INTERVAL    0x002
  308. #define    F_NUMERIC    0x004
  309. #define    F_PINGFILLED    0x008
  310. #define    F_QUIET        0x010
  311. #define    F_RROUTE    0x020
  312. #define    F_SO_DEBUG    0x040
  313. #define    F_SO_DONTROUTE    0x080
  314. #define    F_VERBOSE    0x100
  315. #define F_LOOSEROUTE    0x200
  316.  
  317. #ifndef LONG_MAX
  318. #define LONG_MAX 0xffffffff
  319. #endif
  320.  
  321. /*
  322.  * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum
  323.  * number of received sequence numbers we can keep track of.  Change 128
  324.  * to 8192 for complete accuracy...
  325.  */
  326. #define    MAX_DUP_CHK    (8 * 128)
  327. int mx_dup_ck = MAX_DUP_CHK;
  328. char rcvd_tbl[MAX_DUP_CHK / 8];
  329.  
  330. struct sockaddr whereto;    /* who to ping */
  331. int datalen = DEFDATALEN;
  332. int s = -1;            /* socket file descriptor */
  333. u_char *outpack;
  334. char BSPACE = '\b';        /* characters written for flood */
  335. char DOT = '.';
  336. char *hostname;
  337. long ident;            /* process id to identify our packets */
  338.  
  339. /* counters */
  340. long npackets;            /* max packets to transmit */
  341. long nreceived;            /* # of packets we got back */
  342. long nrepeats;            /* number of duplicates */
  343. long ntransmitted;        /* sequence # for outbound packets = #sent */
  344. int interval = 1;        /* interval between packets */
  345.  
  346. /* timing */
  347. int timing;            /* flag to do timing */
  348. long tmin = LONG_MAX;        /* minimum round trip time */
  349. long tmax;            /* maximum round trip time */
  350. u_long tsum;            /* sum of all times, for doing average */
  351.  
  352. char *pr_addr(u_long l);
  353. void catcher(void), pinger(void), finish(void), usage(void);
  354. void pr_pack(char *buf,    int cc,    struct sockaddr_in *from);
  355. void pr_icmph(struct icmp *icp);
  356. void pr_iph(struct ip *ip);
  357. void pr_retip(struct ip *ip);
  358. void fill(char *bp, char *patp);
  359. int in_cksum(u_short *addr, int len);
  360. void tvsub(register struct timeval *out, register struct timeval *in);
  361.  
  362. #ifdef AMIGA
  363. /*
  364.  * Other Amiga dependent stuff
  365.  */
  366. #ifdef __SASC
  367. #include <clib/exec_protos.h>
  368. #include <pragmas/exec_sysbase_pragmas.h>
  369. extern struct ExecBase *SysBase;
  370. /* Disable ^C signaling */
  371. void __regargs __chkabort(void) {}
  372. #else
  373. #include <clib/exec_protos.h>
  374. #endif
  375. #include <dos/dos.h>
  376.  
  377. #define getpid(x) ((ULONG)FindTask(NULL)) /* This is only for ident... */
  378.  
  379. struct MsgPort *timerport = NULL;
  380. struct timerequest *timermsg = NULL;
  381. BOOL notopen = TRUE;
  382. #define TimerBase (timermsg->tr_node.io_Device)
  383.  
  384. void
  385. clean_timer(void)
  386. {
  387.   if (timermsg) {
  388.     if (!notopen) {
  389.       if (!CheckIO((struct IORequest*)timermsg)) {
  390.     AbortIO((struct IORequest*)timermsg);
  391.     WaitIO((struct IORequest*)timermsg);
  392.       }
  393.       CloseDevice((struct IORequest*)timermsg);
  394.       notopen = TRUE;
  395.     }
  396.     DeleteIORequest(timermsg);
  397.     timermsg = NULL;
  398.   }
  399.   if (timerport) {
  400.     DeleteMsgPort(timerport);
  401.     timerport = NULL;
  402.   }
  403. }
  404. #endif
  405.  
  406. main(argc, argv)
  407.     int argc;
  408.     char **argv;
  409. {
  410.   extern int errno, optind;
  411.   extern char *optarg;
  412.   struct timeval timeout;
  413.   struct hostent *hp;
  414.   struct sockaddr_in *to;
  415.   struct protoent *proto;
  416.   register int i;
  417.   int ch, fdmask, hold, packlen, preload;
  418.   u_char *datap, *packet;
  419.   char *target, hnamebuf[MAXHOSTNAMELEN];
  420. #ifdef IP_OPTIONS
  421.   u_char rspace[3 + 4 * NROUTES + 1]; /* record route space */
  422. #endif
  423. #ifdef AMIGA
  424.   ULONG timermask;
  425. #endif
  426.   outpack = malloc(MAXPACKET);
  427.   if (outpack == NULL) {
  428.     perror("ping");
  429.     exit(1);
  430.   }
  431.   preload = 0;
  432.   datap = &outpack[8 + sizeof(struct timeval)];
  433.   while ((ch = getopt(argc, argv, "LRc:dfh:i:l:np:qrs:v")) != EOF)
  434.     switch(ch) {
  435.     case 'c':
  436.       npackets = atoi(optarg);
  437.       if (npackets <= 0) {
  438.     (void)fprintf(stderr, "ping: bad number of packets to transmit.\n");
  439.     exit(1);
  440.       }
  441.       break;
  442.     case 'd':
  443.       options |= F_SO_DEBUG;
  444.       break;
  445.     case 'f':
  446. #ifndef AMIGA
  447.       if (getuid()) {
  448.     (void)fprintf(stderr, "ping: %s\n", strerror(EPERM));
  449.     exit(1);
  450.       }
  451. #endif
  452.       options |= F_FLOOD;
  453.       setbuf(stdout, (char *)NULL);
  454.       break;
  455.     case 'i':            /* wait between sending packets */
  456.       interval = atoi(optarg);
  457.       if (interval <= 0) {
  458.     (void)fprintf(stderr, "ping: bad timing interval.\n");
  459.     exit(1);
  460.       }
  461.       options |= F_INTERVAL;
  462.       break;
  463.     case 'L':
  464.       options |= F_LOOSEROUTE;
  465.       break;
  466.     case 'l':
  467.       preload = atoi(optarg);
  468.       if (preload < 0) {
  469.     (void)fprintf(stderr, "ping: bad preload value.\n");
  470.     exit(1);
  471.       }
  472.       break;
  473.     case 'n':
  474.       options |= F_NUMERIC;
  475.       break;
  476.     case 'p':            /* fill buffer with user pattern */
  477.       options |= F_PINGFILLED;
  478.       fill((char *)datap, optarg);
  479.       break;
  480.     case 'q':
  481.       options |= F_QUIET;
  482.       break;
  483.     case 'R':
  484.       options |= F_RROUTE;
  485.       break;
  486.     case 'r':
  487.       options |= F_SO_DONTROUTE;
  488.       break;
  489.     case 's':            /* size of packet to send */
  490.       datalen = atoi(optarg);
  491.       if (datalen > MAXPACKET) {
  492.     (void)fprintf(stderr, "ping: packet size too large.\n");
  493.     exit(1);
  494.       }
  495.       if (datalen <= 0) {
  496.     (void)fprintf(stderr, "ping: illegal packet size.\n");
  497.     exit(1);
  498.       }
  499.       break;
  500.     case 'v':
  501.       options |= F_VERBOSE;
  502.       break;
  503.     default:
  504.       usage();
  505.     }
  506.   argc -= optind;
  507.   argv += optind;
  508.  
  509.   if (argc < 1 || (options & F_LOOSEROUTE) == 0 && argc > 1)
  510.     usage();
  511.  
  512.   if ((options & (F_LOOSEROUTE | F_RROUTE)) == (F_LOOSEROUTE | F_RROUTE)) {
  513.     fprintf(stderr, "ping: -L and -R options cannot be used concurrently\n");
  514.     exit(1);
  515.   }
  516.  
  517.   {
  518.     u_char *cp = rspace;
  519.  
  520.     if (options & F_LOOSEROUTE) {
  521. #ifdef IP_OPTIONS
  522.       rspace[IPOPT_OPTVAL] = IPOPT_LSRR;
  523.       rspace[IPOPT_OLEN] = 3;
  524.       rspace[IPOPT_OFFSET] = IPOPT_MINOFF;
  525.       cp = rspace + IPOPT_OFFSET + 1;
  526. #else
  527.       (void)fprintf(stderr, "ping: source routing not "
  528.             "available in this implementation.\n");
  529.       exit(1);
  530. #endif                /* IP_OPTIONS */
  531.     }
  532.  
  533.     while (target = *argv++) {
  534.       bzero((char *)&whereto, sizeof(struct sockaddr));
  535.       to = (struct sockaddr_in *)&whereto;
  536. #ifdef _SOCKADDR_LEN
  537.       to->sin_len = sizeof(*to);
  538. #endif
  539.       to->sin_family = AF_INET;
  540.       to->sin_addr.s_addr = inet_addr(target);
  541.       if (to->sin_addr.s_addr != (u_int)-1)
  542.     hostname = target;
  543.       else {
  544.     hp = gethostbyname(target);
  545.     if (!hp) {
  546.       fprintf(stderr, "ping: unknown host %s\n", target);
  547.       exit(1);
  548.     }
  549.     to->sin_family = hp->h_addrtype;
  550.     bcopy(hp->h_addr, (caddr_t)&to->sin_addr, hp->h_length);
  551.     (void)strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf) - 1);
  552.     hostname = hnamebuf;
  553.       }
  554.  
  555. #ifdef IP_OPTIONS
  556.       if (options & F_LOOSEROUTE) {
  557.     if (rspace + sizeof(rspace) - 4 < cp) {
  558.       fprintf(stderr, "ping: too many hops for "
  559.           "source routing %s\n", target);
  560.       exit(1);
  561.     }
  562.     *cp++ = (to->sin_addr.s_addr >> 24);
  563.     *cp++ = (to->sin_addr.s_addr >> 16);
  564.     *cp++ = (to->sin_addr.s_addr >> 8);
  565.     *cp++ = (to->sin_addr.s_addr >> 0);
  566.     rspace[IPOPT_OLEN] += 4;
  567.       }
  568. #endif
  569.     }
  570.   }
  571.  
  572.   if (options & F_FLOOD && options & F_INTERVAL) {
  573.     (void)fprintf(stderr, "ping: -f and -i incompatible options.\n");
  574.     exit(1);
  575.   }
  576.  
  577.   if (datalen >= sizeof(struct timeval)) /* can we time transfer */
  578.     timing = 1;
  579.   packlen = datalen + MAXIPLEN + MAXICMPLEN;
  580.   if (!(packet = (u_char *)malloc((u_int)packlen))) {
  581.     (void)fprintf(stderr, "ping: out of memory.\n");
  582.     exit(1);
  583.   }
  584.   if (!(options & F_PINGFILLED))
  585.     for (i = 8; i < datalen; ++i)
  586.       *datap++ = i;
  587.  
  588.   ident = getpid() & 0xFFFF;
  589.  
  590.   if (!(proto = getprotobyname("icmp"))) {
  591.     (void)fprintf(stderr, "ping: unknown protocol icmp.\n");
  592.     exit(1);
  593.   }
  594.  
  595. #ifdef AMIGA
  596.   atexit(clean_timer);
  597.  
  598.   timerport = CreateMsgPort();
  599.   if (!timerport) {
  600.     (void)fprintf(stderr, "ping: could not create timer port.\n");
  601.     exit(1);
  602.   }
  603.   timermask = 1<<timerport->mp_SigBit;
  604.  
  605.   timermsg = CreateIORequest(timerport, sizeof(*timermsg));
  606.   if (!timermsg) {
  607.     (void)fprintf(stderr, "ping: could not create timer message.\n");
  608.     exit(1);
  609.   }
  610.  
  611.   if (notopen = OpenDevice("timer.device", UNIT_MICROHZ,
  612.          (struct IORequest *)timermsg, 0)) {
  613.     (void)fprintf(stderr, "ping: could not open timer device.\n");
  614.     exit(1);
  615.   }
  616.  
  617.   timermsg->tr_node.io_Command = TR_ADDREQUEST;
  618.   timermsg->tr_time.tv_secs = 1L;
  619.   timermsg->tr_time.tv_micro = 0L;
  620.   /* don't confuse CheckIO */
  621.   timermsg->tr_node.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
  622.   SetSocketSignals(timermask | SIGBREAKF_CTRL_C, 0L, 0L);
  623. #endif
  624.  
  625.   if ((s = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0) {
  626.     perror("ping: socket");
  627.     exit(1);
  628.   }
  629.   hold = 1;
  630.   if (options & F_SO_DEBUG)
  631.     (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold,
  632.              sizeof(hold));
  633.   if (options & F_SO_DONTROUTE)
  634.     (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&hold,
  635.              sizeof(hold));
  636.  
  637. #ifdef IP_OPTIONS
  638.   if (options & F_LOOSEROUTE) {
  639.     /* pad to long word */
  640.     rspace[rspace[IPOPT_OLEN]] = IPOPT_EOL;
  641.     if (setsockopt(s, IPPROTO_IP, IP_OPTIONS, rspace,
  642.            rspace[IPOPT_OLEN] + 1) < 0) {
  643.       perror("ping: source routing");
  644.       exit(1);
  645.     }
  646.   }
  647. #endif
  648.  
  649.   /* record route option */
  650.   if (options & F_RROUTE) {
  651. #ifdef IP_OPTIONS
  652.     rspace[IPOPT_OPTVAL] = IPOPT_RR;
  653.     rspace[IPOPT_OLEN] = sizeof(rspace)-1;
  654.     rspace[IPOPT_OFFSET] = IPOPT_MINOFF;
  655.     rspace[rspace[IPOPT_OLEN]] = IPOPT_EOL;
  656.     if (setsockopt(s, IPPROTO_IP, IP_OPTIONS, rspace,
  657.            sizeof(rspace)) < 0) {
  658.       perror("ping: record route");
  659.       exit(1);
  660.     }
  661. #else
  662.     (void)fprintf(stderr,
  663.           "ping: record route not available in this implementation.\n");
  664.     exit(1);
  665. #endif                /* IP_OPTIONS */
  666.   }
  667.  
  668.   /*
  669.    * When pinging the broadcast address, you can get a lot of answers.
  670.    * Doing something so evil is useful if you are trying to stress the
  671.    * ethernet, or just want to fill the arp cache to get some stuff for
  672.    * /etc/ethers.
  673.    */
  674.   hold = 48 * 1024;
  675.   (void)setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold,
  676.            sizeof(hold));
  677.  
  678.   if (to->sin_family == AF_INET)
  679.     (void)printf("PING %s (%s): %d data bytes\n", hostname,
  680.          inet_ntoa(*(struct in_addr *)&to->sin_addr.s_addr),
  681.          datalen);
  682.   else
  683.     (void)printf("PING %s: %d data bytes\n", hostname, datalen);
  684.  
  685. #ifndef AMIGA
  686.   (void)signal(SIGINT, finish);
  687.   (void)signal(SIGALRM, catcher);
  688. #endif
  689.  
  690.   while (preload--)        /* fire off them quickies */
  691.     pinger();
  692.  
  693.   if ((options & F_FLOOD) == 0)
  694.     catcher();            /* start things going */
  695.  
  696.   for (;;) {
  697.     struct sockaddr_in from;
  698.     register int cc;
  699.     int fromlen;
  700.  
  701. #ifdef AMIGA
  702.     /* Check for special signals */
  703.     ULONG sm = SetSignal(0L, timermask | SIGBREAKF_CTRL_C);
  704.     if (sm & SIGBREAKF_CTRL_C)
  705.       finish();
  706.     if (sm & timermask && GetMsg(timerport))
  707.       catcher();
  708. #endif
  709.  
  710.     if (options & F_FLOOD) {
  711.       pinger();
  712.       timeout.tv_sec = 0;
  713.       timeout.tv_usec = 10000;
  714.       fdmask = 1 << s;
  715.       if (select(s + 1, (fd_set *)&fdmask, (fd_set *)NULL,
  716.          (fd_set *)NULL, &timeout) < 1)
  717.     continue;
  718.     }
  719.     fromlen = sizeof(from);
  720.     if ((cc = recvfrom(s, (char *)packet, packlen, 0,
  721.                (struct sockaddr *)&from, &fromlen)) < 0) {
  722.       if (errno == EINTR)
  723.     continue;
  724.       perror("ping: recvfrom");
  725.       continue;
  726.     }
  727.     pr_pack((char *)packet, cc, &from);
  728.     if (npackets && nreceived >= npackets)
  729.       break;
  730.   }
  731.   finish();
  732.   /* NOTREACHED */
  733. }
  734.  
  735. /*
  736.  * catcher --
  737.  *    This routine causes another PING to be transmitted, and then
  738.  * schedules another SIGALRM for 1 second from now.
  739.  *
  740.  * bug --
  741.  *    Our sense of time will slowly skew (i.e., packets will not be
  742.  * launched exactly at 1-second intervals).  This does not affect the
  743.  * quality of the delay and loss statistics.
  744.  *
  745.  * notes --
  746.  *      This routine uses timer.device in Amiga implementation instead
  747.  * of SIGALRM.
  748.  */
  749. void
  750. catcher()
  751. {
  752. #ifdef AMIGA
  753.   static int waittime = 0;
  754.  
  755.   if (waittime)
  756.     finish();
  757.  
  758.   pinger();
  759.  
  760.   if (!npackets || ntransmitted < npackets) {
  761.     timermsg->tr_time.tv_sec = interval;
  762.     SendIO((struct IORequest*)timermsg);
  763.   } else {
  764.     if (nreceived) {
  765.       waittime = 2 * tmax / 1000;
  766.       if (!waittime)
  767.     waittime = 1;
  768.     } else
  769.       waittime = MAXWAIT;
  770.     timermsg->tr_time.tv_sec = waittime;
  771.     SendIO((struct IORequest*)timermsg);
  772.   }
  773. #else
  774.     int waittime;
  775.  
  776.     pinger();
  777.     (void)signal(SIGALRM, catcher);
  778.     if (!npackets || ntransmitted < npackets)
  779.         alarm((u_int)interval);
  780.     else {
  781.         if (nreceived) {
  782.             waittime = 2 * tmax / 1000;
  783.             if (!waittime)
  784.                 waittime = 1;
  785.         } else
  786.             waittime = MAXWAIT;
  787.         (void)signal(SIGALRM, finish);
  788.         (void)alarm((u_int)waittime);
  789.     }
  790. #endif
  791. }
  792.  
  793. /*
  794.  * pinger --
  795.  *     Compose and transmit an ICMP ECHO REQUEST packet.  The IP packet
  796.  * will be added on by the kernel.  The ID field is our process ID,
  797.  * and the sequence number is an ascending integer.  The first 8 bytes
  798.  * of the data portion are used to hold a UNIX "timeval" struct in native
  799.  * byte-order, to compute the round-trip time.
  800.  */
  801. void
  802. pinger()
  803. {
  804.     register struct icmp *icp;
  805.     register int cc;
  806.     int i;
  807.  
  808.     icp = (struct icmp *)outpack;
  809.     icp->icmp_type = ICMP_ECHO;
  810.     icp->icmp_code = 0;
  811.     icp->icmp_cksum = 0;
  812.     icp->icmp_seq = ntransmitted++;
  813.     icp->icmp_id = ident;            /* ID */
  814.  
  815.     CLR(icp->icmp_seq % mx_dup_ck);
  816.  
  817.     if (timing)
  818. #ifdef AMIGA
  819.         (void)ReadEClock((struct EClockVal *)&outpack[8]);
  820. #else
  821.         (void)gettimeofday((struct timeval *)&outpack[8],
  822.             (struct timezone *)NULL);
  823. #endif
  824.     cc = datalen + 8;            /* skips ICMP portion */
  825.  
  826.     /* compute ICMP checksum here */
  827.     icp->icmp_cksum = in_cksum((u_short *)icp, cc);
  828.  
  829.     i = sendto(s, (char *)outpack, cc, 0, &whereto,
  830.         sizeof(struct sockaddr));
  831.  
  832.     if (i < 0 || i != cc)  {
  833.         if (i < 0)
  834.             perror("ping: sendto");
  835.         (void)printf("ping: wrote %s %d chars, ret=%d\n",
  836.             hostname, cc, i);
  837.     }
  838.     if (!(options & F_QUIET) && options & F_FLOOD)
  839.         (void)write(1, &DOT, 1);
  840. }
  841.  
  842. /*
  843.  * pr_pack --
  844.  *    Print out the packet, if it came from us.  This logic is necessary
  845.  * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
  846.  * which arrive ('tis only fair).  This permits multiple copies of this
  847.  * program to be run without having intermingled output (or statistics!).
  848.  */
  849. void
  850. pr_pack(buf, cc, from)
  851.     char *buf;
  852.     int cc;
  853.     struct sockaddr_in *from;
  854. {
  855.     register struct icmp *icp;
  856.     register u_long l;
  857.     register int i, j;
  858.     register u_char *cp,*dp;
  859.     static int old_rrlen;
  860.     static char old_rr[MAX_IPOPTLEN];
  861.     struct ip *ip;
  862.     struct timeval tv, *tp;
  863.     long triptime;
  864.     int hlen, dupflag;
  865.  
  866. #ifdef AMIGA
  867.     ULONG efreq = ReadEClock((struct EClockVal *)&tv);
  868. #else
  869.     (void)gettimeofday(&tv, (struct timezone *)NULL);
  870. #endif
  871.     /* Check the IP header */
  872.     ip = (struct ip *)buf;
  873.     hlen = ip->ip_hl << 2;
  874.     if (cc < hlen + ICMP_MINLEN) {
  875.         if (options & F_VERBOSE)
  876.             (void)fprintf(stderr,
  877.               "ping: packet too short (%d bytes) from %s\n", cc,
  878.               inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr));
  879.         return;
  880.     }
  881.  
  882.     /* Now the ICMP part */
  883.     cc -= hlen;
  884.     icp = (struct icmp *)(buf + hlen);
  885.     if (icp->icmp_type == ICMP_ECHOREPLY) {
  886.         if (icp->icmp_id != ident)
  887.             return;            /* 'Twas not our ECHO */
  888.         ++nreceived;
  889.         if (timing) {
  890. #ifndef icmp_data
  891.             tp = (struct timeval *)&icp->icmp_ip;
  892. #else
  893.             tp = (struct timeval *)icp->icmp_data;
  894. #endif
  895. #ifdef AMIGA
  896.             /* EClockVal is actually a unsigned long long */
  897.             if (tv.tv_micro < tp->tv_micro)
  898.               tv.tv_sec--;
  899.             tv.tv_micro -= tp->tv_micro;
  900.             tv.tv_secs  -= tp->tv_secs;
  901.             triptime = tv.tv_micro / (efreq / 1000);
  902.             if (tv.tv_secs)
  903.               triptime += tv.tv_sec * 250 * ((1<<30) / efreq);
  904. #else
  905.             tvsub(&tv, tp);
  906.             triptime = tv.tv_sec * 1000 + (tv.tv_usec / 1000);
  907. #endif
  908.             tsum += triptime;
  909.             if (triptime < tmin)
  910.                 tmin = triptime;
  911.             if (triptime > tmax)
  912.                 tmax = triptime;
  913.         }
  914.  
  915.         if (TST(icp->icmp_seq % mx_dup_ck)) {
  916.             ++nrepeats;
  917.             --nreceived;
  918.             dupflag = 1;
  919.         } else {
  920.             SET(icp->icmp_seq % mx_dup_ck);
  921.             dupflag = 0;
  922.         }
  923.  
  924.         if (options & F_QUIET)
  925.             return;
  926.  
  927.         if (options & F_FLOOD)
  928.             (void)write(1, &BSPACE, 1);
  929.         else {
  930.             (void)printf("%d bytes from %s: icmp_seq=%u", cc,
  931.                inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr),
  932.                icp->icmp_seq);
  933.             (void)printf(" ttl=%d", ip->ip_ttl);
  934.             if (timing)
  935.                 (void)printf(" time=%ld ms", triptime);
  936.             if (dupflag)
  937.                 (void)printf(" (DUP!)");
  938.             /* check the data */
  939.             cp = (u_char*)&icp->icmp_data[8];
  940.             dp = &outpack[8 + sizeof(struct timeval)];
  941.             for (i = 8; i < datalen; ++i, ++cp, ++dp) {
  942.                 if (*cp != *dp) {
  943.     (void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x",
  944.         i, *dp, *cp);
  945.                     cp = (u_char*)&icp->icmp_data[0];
  946.                     for (i = 8; i < datalen; ++i, ++cp) {
  947.                         if ((i % 32) == 8)
  948.                             (void)printf("\n\t");
  949.                         (void)printf("%x ", *cp);
  950.                     }
  951.                     break;
  952.                 }
  953.             }
  954.         }
  955.     } else {
  956.         /* We've got something other than an ECHOREPLY */
  957.         if (!(options & F_VERBOSE))
  958.             return;
  959.         (void)printf("%d bytes from %s: ", cc,
  960.             pr_addr(from->sin_addr.s_addr));
  961.         pr_icmph(icp);
  962.     }
  963.  
  964.     /* Display any IP options */
  965.     /* The LSRR and RR len handling was broken (?) //ppessi */
  966.     cp = (u_char *)buf + sizeof(struct ip);
  967.  
  968.     for (; hlen > (int)sizeof(struct ip); --hlen, ++cp)
  969.         switch (*cp) {
  970.         case IPOPT_EOL:
  971.             hlen = 0;
  972.             break;
  973.         case IPOPT_LSRR:
  974.         case IPOPT_SSRR:
  975.             (void)printf(*cp == IPOPT_LSRR ?
  976.                      "\nLSRR: " : "\nSSRR: ");
  977.             j = *++cp;
  978.             ++cp;
  979.             hlen -= j;
  980.             if (j > IPOPT_MINOFF)
  981.                 for (;;) {
  982.                     l = *++cp;
  983.                     l = (l<<8) + *++cp;
  984.                     l = (l<<8) + *++cp;
  985.                     l = (l<<8) + *++cp;
  986.                     if (l == 0)
  987.                         (void)printf("\t0.0.0.0");
  988.                     else
  989.                         (void)printf("\t%s", pr_addr(ntohl(l)));
  990.                     j -= 4;
  991.                     if (j < IPOPT_MINOFF)
  992.                         break;
  993.                     (void)putchar('\n');
  994.                 }
  995.             break;
  996.         case IPOPT_RR:
  997.             j = *++cp;        /* get length */
  998.             i = *++cp;        /* and pointer */
  999.             hlen -= j;
  1000.             if (i > j)
  1001.                 i = j;
  1002.             i -= IPOPT_MINOFF;
  1003.             if (i <= 0)
  1004.                 continue;
  1005.             if (i == old_rrlen
  1006.                 && cp == (u_char *)buf + sizeof(struct ip) + 2
  1007.                 && !bcmp((char *)cp, old_rr, i)
  1008.                 && !(options & F_FLOOD)) {
  1009.                 (void)printf("\t(same route)");
  1010.                 i = ((i + 3) / 4) * 4;
  1011.                 cp += i;
  1012.                 break;
  1013.             }
  1014.             old_rrlen = i;
  1015.             bcopy((char *)cp, old_rr, i);
  1016.             (void)printf("\nRR: ");
  1017.             for (;;) {
  1018.                 l = *++cp;
  1019.                 l = (l<<8) + *++cp;
  1020.                 l = (l<<8) + *++cp;
  1021.                 l = (l<<8) + *++cp;
  1022.                 if (l == 0)
  1023.                     (void)printf("\t0.0.0.0");
  1024.                 else
  1025.                     (void)printf("\t%s", pr_addr(ntohl(l)));
  1026.                 i -= 4;
  1027.                 if (i <= 0)
  1028.                     break;
  1029.                 (void)putchar('\n');
  1030.             }
  1031.             break;
  1032.         case IPOPT_NOP:
  1033.             (void)printf("\nNOP");
  1034.             break;
  1035.         default:
  1036.             (void)printf("\nunknown option %x", *cp);
  1037.             break;
  1038.         }
  1039.     if (!(options & F_FLOOD)) {
  1040.         (void)putchar('\n');
  1041.         (void)fflush(stdout);
  1042.     }
  1043. }
  1044.  
  1045. /*
  1046.  * in_cksum --
  1047.  *    Checksum routine for Internet Protocol family headers (C Version)
  1048.  */
  1049. int
  1050. in_cksum(addr, len)
  1051.     u_short *addr;
  1052.     int len;
  1053. {
  1054.     register int nleft = len;
  1055.     register u_short *w = addr;
  1056.     register int sum = 0;
  1057.     u_short answer = 0;
  1058.  
  1059.     /*
  1060.      * Our algorithm is simple, using a 32 bit accumulator (sum), we add
  1061.      * sequential 16 bit words to it, and at the end, fold back all the
  1062.      * carry bits from the top 16 bits into the lower 16 bits.
  1063.      */
  1064.     while (nleft > 1)  {
  1065.         sum += *w++;
  1066.         nleft -= 2;
  1067.     }
  1068.  
  1069.     /* mop up an odd byte, if necessary */
  1070.     if (nleft == 1) {
  1071.         *(u_char *)(&answer) = *(u_char *)w ;
  1072.         sum += answer;
  1073.     }
  1074.  
  1075.     /* add back carry outs from top 16 bits to low 16 bits */
  1076.     sum = (sum >> 16) + (sum & 0xffff);    /* add hi 16 to low 16 */
  1077.     sum += (sum >> 16);            /* add carry */
  1078.     answer = ~sum;                /* truncate to 16 bits */
  1079.     return(answer);
  1080. }
  1081.  
  1082. /*
  1083.  * tvsub --
  1084.  *    Subtract 2 timeval structs:  out = out - in.  Out is assumed to
  1085.  * be >= in.
  1086.  */
  1087. void
  1088. tvsub(out, in)
  1089.     register struct timeval *out, *in;
  1090. {
  1091.     if ((out->tv_usec -= in->tv_usec) < 0) {
  1092.         --out->tv_sec;
  1093.         out->tv_usec += 1000000;
  1094.     }
  1095.     out->tv_sec -= in->tv_sec;
  1096. }
  1097.  
  1098. /*
  1099.  * finish --
  1100.  *    Print out statistics, and give up.
  1101.  */
  1102. void
  1103. finish()
  1104. {
  1105.     (void)signal(SIGINT, SIG_IGN);
  1106.     (void)putchar('\n');
  1107.     (void)fflush(stdout);
  1108.     (void)printf("--- %s ping statistics ---\n", hostname);
  1109.     (void)printf("%ld packets transmitted, ", ntransmitted);
  1110.     (void)printf("%ld packets received, ", nreceived);
  1111.     if (nrepeats)
  1112.         (void)printf("+%ld duplicates, ", nrepeats);
  1113.     if (ntransmitted)
  1114.         if (nreceived > ntransmitted)
  1115.             (void)printf("-- somebody's printing up packets!");
  1116.         else
  1117.             (void)printf("%d%% packet loss",
  1118.                 (int) (((ntransmitted - nreceived) * 100) /
  1119.                 ntransmitted));
  1120.     (void)putchar('\n');
  1121.     if (nreceived && timing)
  1122.         (void)printf("round-trip min/avg/max = %ld/%lu/%ld ms\n",
  1123.             tmin, tsum / (nreceived + nrepeats), tmax);
  1124.     exit(0);
  1125. }
  1126.  
  1127. #ifdef notdef
  1128. static char *ttab[] = {
  1129.     "Echo Reply",        /* ip + seq + udata */
  1130.     "Dest Unreachable",    /* net, host, proto, port, frag, sr + IP */
  1131.     "Source Quench",    /* IP */
  1132.     "Redirect",        /* redirect type, gateway, + IP  */
  1133.     "Echo",
  1134.     "Time Exceeded",    /* transit, frag reassem + IP */
  1135.     "Parameter Problem",    /* pointer + IP */
  1136.     "Timestamp",        /* id + seq + three timestamps */
  1137.     "Timestamp Reply",    /* " */
  1138.     "Info Request",        /* id + sq */
  1139.     "Info Reply"        /* " */
  1140. };
  1141. #endif
  1142.  
  1143. /*
  1144.  * pr_icmph --
  1145.  *    Print a descriptive string about an ICMP header.
  1146.  */
  1147. void
  1148. pr_icmph(icp)
  1149.     struct icmp *icp;
  1150. {
  1151.     switch(icp->icmp_type) {
  1152.     case ICMP_ECHOREPLY:
  1153.         (void)printf("Echo Reply\n");
  1154.         /* XXX ID + Seq + Data */
  1155.         break;
  1156.     case ICMP_UNREACH:
  1157.         switch(icp->icmp_code) {
  1158.         case ICMP_UNREACH_NET:
  1159.             (void)printf("Destination Net Unreachable\n");
  1160.             break;
  1161.         case ICMP_UNREACH_HOST:
  1162.             (void)printf("Destination Host Unreachable\n");
  1163.             break;
  1164.         case ICMP_UNREACH_PROTOCOL:
  1165.             (void)printf("Destination Protocol Unreachable\n");
  1166.             break;
  1167.         case ICMP_UNREACH_PORT:
  1168.             (void)printf("Destination Port Unreachable\n");
  1169.             break;
  1170.         case ICMP_UNREACH_NEEDFRAG:
  1171.             (void)printf("frag needed and DF set\n");
  1172.             break;
  1173.         case ICMP_UNREACH_SRCFAIL:
  1174.             (void)printf("Source Route Failed\n");
  1175.             break;
  1176.         default:
  1177.             (void)printf("Dest Unreachable, Bad Code: %d\n",
  1178.                 icp->icmp_code);
  1179.             break;
  1180.         }
  1181.         /* Print returned IP header information */
  1182. #ifndef icmp_data
  1183.         pr_retip(&icp->icmp_ip);
  1184. #else
  1185.         pr_retip((struct ip *)icp->icmp_data);
  1186. #endif
  1187.         break;
  1188.     case ICMP_SOURCEQUENCH:
  1189.         (void)printf("Source Quench\n");
  1190. #ifndef icmp_data
  1191.         pr_retip(&icp->icmp_ip);
  1192. #else
  1193.         pr_retip((struct ip *)icp->icmp_data);
  1194. #endif
  1195.         break;
  1196.     case ICMP_REDIRECT:
  1197.         switch(icp->icmp_code) {
  1198.         case ICMP_REDIRECT_NET:
  1199.             (void)printf("Redirect Network");
  1200.             break;
  1201.         case ICMP_REDIRECT_HOST:
  1202.             (void)printf("Redirect Host");
  1203.             break;
  1204.         case ICMP_REDIRECT_TOSNET:
  1205.             (void)printf("Redirect Type of Service and Network");
  1206.             break;
  1207.         case ICMP_REDIRECT_TOSHOST:
  1208.             (void)printf("Redirect Type of Service and Host");
  1209.             break;
  1210.         default:
  1211.             (void)printf("Redirect, Bad Code: %d", icp->icmp_code);
  1212.             break;
  1213.         }
  1214.         (void)printf("(New addr: 0x%08lx)\n", icp->icmp_gwaddr.s_addr);
  1215. #ifndef icmp_data
  1216.         pr_retip(&icp->icmp_ip);
  1217. #else
  1218.         pr_retip((struct ip *)icp->icmp_data);
  1219. #endif
  1220.         break;
  1221.     case ICMP_ECHO:
  1222.         (void)printf("Echo Request\n");
  1223.         /* XXX ID + Seq + Data */
  1224.         break;
  1225.     case ICMP_TIMXCEED:
  1226.         switch(icp->icmp_code) {
  1227.         case ICMP_TIMXCEED_INTRANS:
  1228.             (void)printf("Time to live exceeded\n");
  1229.             break;
  1230.         case ICMP_TIMXCEED_REASS:
  1231.             (void)printf("Frag reassembly time exceeded\n");
  1232.             break;
  1233.         default:
  1234.             (void)printf("Time exceeded, Bad Code: %d\n",
  1235.                 icp->icmp_code);
  1236.             break;
  1237.         }
  1238. #ifndef icmp_data
  1239.         pr_retip(&icp->icmp_ip);
  1240. #else
  1241.         pr_retip((struct ip *)icp->icmp_data);
  1242. #endif
  1243.         break;
  1244.     case ICMP_PARAMPROB:
  1245.         (void)printf("Parameter problem: pointer = 0x%02x\n",
  1246.             icp->icmp_hun.ih_pptr);
  1247. #ifndef icmp_data
  1248.         pr_retip(&icp->icmp_ip);
  1249. #else
  1250.         pr_retip((struct ip *)icp->icmp_data);
  1251. #endif
  1252.         break;
  1253.     case ICMP_TSTAMP:
  1254.         (void)printf("Timestamp\n");
  1255.         /* XXX ID + Seq + 3 timestamps */
  1256.         break;
  1257.     case ICMP_TSTAMPREPLY:
  1258.         (void)printf("Timestamp Reply\n");
  1259.         /* XXX ID + Seq + 3 timestamps */
  1260.         break;
  1261.     case ICMP_IREQ:
  1262.         (void)printf("Information Request\n");
  1263.         /* XXX ID + Seq */
  1264.         break;
  1265.     case ICMP_IREQREPLY:
  1266.         (void)printf("Information Reply\n");
  1267.         /* XXX ID + Seq */
  1268.         break;
  1269. #ifdef ICMP_MASKREQ
  1270.     case ICMP_MASKREQ:
  1271.         (void)printf("Address Mask Request\n");
  1272.         break;
  1273. #endif
  1274. #ifdef ICMP_MASKREPLY
  1275.     case ICMP_MASKREPLY:
  1276.         (void)printf("Address Mask Reply\n");
  1277.         break;
  1278. #endif
  1279.     default:
  1280.         (void)printf("Bad ICMP type: %d\n", icp->icmp_type);
  1281.     }
  1282. }
  1283.  
  1284. /*
  1285.  * pr_iph --
  1286.  *    Print an IP header with options.
  1287.  */
  1288. void
  1289. pr_iph(ip)
  1290.     struct ip *ip;
  1291. {
  1292.     int hlen;
  1293.     u_char *cp;
  1294.  
  1295.     hlen = ip->ip_hl << 2;
  1296.     cp = (u_char *)ip + 20;        /* point to options */
  1297.  
  1298.     (void)printf("Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src      Dst Data\n");
  1299.     (void)printf(" %1x  %1x  %02x %04x %04x",
  1300.         ip->ip_v, ip->ip_hl, ip->ip_tos, ip->ip_len, ip->ip_id);
  1301.     (void)printf("   %1x %04x", ((ip->ip_off) & 0xe000) >> 13,
  1302.         (ip->ip_off) & 0x1fff);
  1303.     (void)printf("  %02x  %02x %04x", ip->ip_ttl, ip->ip_p, ip->ip_sum);
  1304.     (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_src.s_addr));
  1305.     (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_dst.s_addr));
  1306.     /* dump and option bytes */
  1307.     while (hlen-- > 20) {
  1308.         (void)printf("%02x", *cp++);
  1309.     }
  1310.     (void)putchar('\n');
  1311. }
  1312.  
  1313. /*
  1314.  * pr_addr --
  1315.  *    Return an ascii host address as a dotted quad and optionally with
  1316.  * a hostname.
  1317.  */
  1318. char *
  1319. pr_addr(l)
  1320.     u_long l;
  1321. {
  1322.     struct hostent *hp;
  1323.     static char buf[80];
  1324.  
  1325.     if ((options & F_NUMERIC) ||
  1326.         !(hp = gethostbyaddr((char *)&l, 4, AF_INET)))
  1327.         (void)sprintf(buf, "%s", inet_ntoa(*(struct in_addr *)&l));
  1328.     else
  1329.         (void)sprintf(buf, "%s (%s)", hp->h_name,
  1330.             inet_ntoa(*(struct in_addr *)&l));
  1331.     return(buf);
  1332. }
  1333.  
  1334. /*
  1335.  * pr_retip --
  1336.  *    Dump some info on a returned (via ICMP) IP packet.
  1337.  */
  1338. void
  1339. pr_retip(ip)
  1340.     struct ip *ip;
  1341. {
  1342.     int hlen;
  1343.     u_char *cp;
  1344.  
  1345.     pr_iph(ip);
  1346.     hlen = ip->ip_hl << 2;
  1347.     cp = (u_char *)ip + hlen;
  1348.  
  1349.     if (ip->ip_p == 6)
  1350.         (void)printf("TCP: from port %u, to port %u (decimal)\n",
  1351.             (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3)));
  1352.     else if (ip->ip_p == 17)
  1353.         (void)printf("UDP: from port %u, to port %u (decimal)\n",
  1354.             (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3)));
  1355. }
  1356.  
  1357. void
  1358. fill(bp, patp)
  1359.     char *bp, *patp;
  1360. {
  1361.     register int ii, jj, kk;
  1362.     int pat[16];
  1363.     char *cp;
  1364.  
  1365.     for (cp = patp; *cp; cp++)
  1366.         if (!isxdigit(*cp)) {
  1367.             (void)fprintf(stderr,
  1368.                 "ping: patterns must be specified as hex digits.\n");
  1369.             exit(1);
  1370.         }
  1371.     ii = sscanf(patp,
  1372.         "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
  1373.         &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6],
  1374.         &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12],
  1375.         &pat[13], &pat[14], &pat[15]);
  1376.  
  1377.     if (ii > 0)
  1378.         for (kk = 0; kk <= MAXPACKET - (8 + ii); kk += ii)
  1379.             for (jj = 0; jj < ii; ++jj)
  1380.                 bp[jj + kk] = pat[jj];
  1381.     if (!(options & F_QUIET)) {
  1382.         (void)printf("PATTERN: 0x");
  1383.         for (jj = 0; jj < ii; ++jj)
  1384.             (void)printf("%02x", bp[jj] & 0xFF);
  1385.         (void)printf("\n");
  1386.     }
  1387. }
  1388.  
  1389. void
  1390. usage()
  1391. {
  1392.     (void)fprintf(stderr,
  1393.         "usage: ping [-Rdfnqrv] [-c count] [-i wait] [-l preload]\n"
  1394.               "\t[-p pattern] [-s packetsize] [-L [hosts]] host\n");
  1395.     exit(1);
  1396. }
  1397.